.log_level = LOG_WARNING,
.log_level_cmdline = false,
.log_syslog = true,
+ .default_duid = { 0 },
+ .default_duid_len = 0,
};
struct sys_conf sys_conf = {
.params = system_attrs,
};
+enum {
+ GLOBAL_ATTR_DUID,
+ GLOBAL_ATTR_MAX
+};
+
+static const struct blobmsg_policy global_attrs[GLOBAL_ATTR_MAX] = {
+ [GLOBAL_ATTR_DUID] = { .name = "dhcp_default_duid", .type = BLOBMSG_TYPE_STRING },
+};
+
+const struct uci_blob_param_list global_attr_list = {
+ .n_params = GLOBAL_ATTR_MAX,
+ .params = global_attrs,
+};
+
static const struct { const char *name; uint8_t flag; } ra_flags[] = {
{ .name = "managed-config", .flag = ND_RA_FLAG_MANAGED },
{ .name = "other-config", .flag = ND_RA_FLAG_OTHER },
return 0;
}
+static void set_global_config(struct uci_section *s)
+{
+ struct blob_attr *tb[GLOBAL_ATTR_MAX], *c;
+
+ blob_buf_init(&b, 0);
+ uci_to_blob(&b, s, &global_attr_list);
+ blobmsg_parse(global_attrs, GLOBAL_ATTR_MAX, tb, blob_data(b.head), blob_len(b.head));
+
+ if ((c = tb[GLOBAL_ATTR_DUID])) {
+ size_t len = blobmsg_data_len(c) / 2;
+
+ config.default_duid_len = 0;
+ if (len >= DUID_MIN_LEN && len <= DUID_MAX_LEN) {
+ ssize_t r = odhcpd_unhexlify(config.default_duid, len, blobmsg_get_string(c));
+ if (r >= DUID_MIN_LEN)
+ config.default_duid_len = r;
+ }
+ }
+}
+
static void set_config(struct uci_section *s)
{
struct blob_attr *tb[ODHCPD_ATTR_MAX], *c;
struct interface *master = NULL, *i, *tmp;
char *uci_dhcp_path = "dhcp";
char *uci_system_path = "system";
+ char *uci_network_path = "network";
if (!uci)
return;
sprintf(uci_dhcp_path, "%s/dhcp", config.uci_cfgdir);
uci_system_path = alloca(dlen + sizeof("/system"));
sprintf(uci_system_path, "%s/system", config.uci_cfgdir);
+ uci_network_path = alloca(dlen + sizeof("/network"));
+ sprintf(uci_network_path, "%s/network", config.uci_cfgdir);
}
vlist_update(&leases);
avl_for_each_element(&interfaces, i, avl)
clean_interface(i);
+ struct uci_package *network = NULL;
+ if (!uci_load(uci, uci_network_path, &network)) {
+ struct uci_element *e;
+
+ /* 0. Global settings */
+ uci_foreach_element(&network->sections, e) {
+ struct uci_section *s = uci_to_section(e);
+ if (!strcmp(s->type, "globals"))
+ set_global_config(s);
+ }
+ }
+ uci_unload(uci, network);
+
struct uci_package *dhcp = NULL;
if (!uci_load(uci, uci_dhcp_path, &dhcp)) {
struct uci_element *e;
- /* 1. Global settings */
+ /* 1. General odhcpd settings */
uci_foreach_element(&dhcp->sections, e) {
struct uci_section *s = uci_to_section(e);
if (!strcmp(s->type, "odhcpd"))
if (config.enable_tz && !uci_load(uci, uci_system_path, &system)) {
struct uci_element *e;
- /* 1. System settings */
+ /* 5. System settings */
uci_foreach_element(&system->sections, e) {
struct uci_section *s = uci_to_section(e);
if (!strcmp(s->type, "system"))
.key = { 0 },
};
- uint8_t duid_ll_hdr[] = { 0x00, 0x03, 0x00, 0x01 };
- memcpy(serverid.data, duid_ll_hdr, sizeof(duid_ll_hdr));
- odhcpd_get_mac(iface, &serverid.data[sizeof(duid_ll_hdr)]);
- serverid.len = htons(sizeof(duid_ll_hdr) + ETH_ALEN);
+ if (config.default_duid_len > 0) {
+ memcpy(serverid.data, config.default_duid, config.default_duid_len);
+ serverid.len = htons(config.default_duid_len);
+ } else {
+ uint16_t duid_ll_hdr[] = { htons(DUID_TYPE_LL), htons(ARPHRD_ETHER) };
+ memcpy(serverid.data, duid_ll_hdr, sizeof(duid_ll_hdr));
+ odhcpd_get_mac(iface, &serverid.data[sizeof(duid_ll_hdr)]);
+ serverid.len = htons(sizeof(duid_ll_hdr) + ETH_ALEN);
+ }
memcpy(clientid.data, assign->clid_data, assign->clid_len);
.serverid_buf = { 0 },
};
- uint8_t duid_ll_hdr[] = { 0x00, 0x03, 0x00, 0x01 };
- memcpy(dest.serverid_buf, duid_ll_hdr, sizeof(duid_ll_hdr));
- odhcpd_get_mac(iface, &dest.serverid_buf[sizeof(duid_ll_hdr)]);
- dest.serverid_length = htons(sizeof(duid_ll_hdr) + ETH_ALEN);
+ if (config.default_duid_len > 0) {
+ memcpy(dest.serverid_buf, config.default_duid, config.default_duid_len);
+ dest.serverid_length = htons(config.default_duid_len);
+ } else {
+ uint16_t duid_ll_hdr[] = { htons(DUID_TYPE_LL), htons(ARPHRD_ETHER) };
+ memcpy(dest.serverid_buf, duid_ll_hdr, sizeof(duid_ll_hdr));
+ odhcpd_get_mac(iface, &dest.serverid_buf[sizeof(duid_ll_hdr)]);
+ dest.serverid_length = htons(sizeof(duid_ll_hdr) + ETH_ALEN);
+ }
struct _packed {
uint16_t type;
OAF_DHCPV6_PD = (1 << 6),
};
+/* 2-byte type + 128-byte DUID, RFC8415, §11.1 */
+#define DUID_MAX_LEN 130
+/* In theory, 2 (type only), or 7 (DUID-EN + 1-byte data), but be reasonable */
+#define DUID_MIN_LEN 10
+#define DUID_HEXSTRLEN (DUID_MAX_LEN * 2 + 1)
+
+enum duid_type {
+ DUID_TYPE_LLT = 1,
+ DUID_TYPE_EN = 2,
+ DUID_TYPE_LL = 3,
+ DUID_TYPE_UUID = 4,
+};
+
struct config {
bool legacy;
bool enable_tz;
int log_level;
bool log_level_cmdline;
bool log_syslog;
+
+ uint8_t default_duid[DUID_MAX_LEN];
+ size_t default_duid_len;
};
struct sys_conf {
size_t tzdb_tz_len;
};
-/* 2-byte type + 128-byte DUID, RFC8415, §11.1 */
-#define DUID_MAX_LEN 130
-#define DUID_HEXSTRLEN (DUID_MAX_LEN * 2 + 1)
-
struct duid {
uint8_t len;
uint8_t id[DUID_MAX_LEN];